/*
    实现缓冲区类的设计
*/

#ifndef __L_BUFFER_H__
#define __L_BUFFER_H__

#include <iostream>
#include <vector>
namespace Log
{

#define DEFAULT_BUFFER_SIZE (10 * 1024 * 1024)   // 缓冲区的默认大小
#define THRESHOLD_BUFFER_SIZE (80 * 1024 * 1024) // 缓冲区大小阈值
#define INCREMENT_BUFFER_SIZE (10 * 1024 * 1024) // 缓冲区大小到达阈值后每次线性增长的大小

    enum class BufferType
    {
        DYNAMICGROW, // 缓冲区动态增长
        STATICSIZE   // 缓冲区固定大小
    };

    class Buffer
    {
    public:
        Buffer(BufferType bufferType = BufferType::STATICSIZE, size_t bufferSize = DEFAULT_BUFFER_SIZE)
        : _bufferType(bufferType), _buffer(bufferSize), _writeIndex(0), _readIndex(0)
        {}

        // 往缓冲区中写入数据
        void push(const char *data, size_t len)
        {
            // 1.先判断缓冲区剩余的大小是否可以写入这些数据 --- 要么动态扩容要么直接返回在外面阻塞等待;
            // 在实际的业务场景中我们不能让缓冲区占用太多的空间, 所以一般都使用固定大小的缓冲区
            // 在日志系统的极限性能测试中我们使用动态扩容的缓冲区
            // 用while判断是防止扩容后缓冲区剩余的大小还无法写入这些数据的情况出现
            while (writeAbleSize() < len)
            {
                if (_bufferType == BufferType::STATICSIZE)
                {
                    // 固定大小类型的缓冲区就直接返回在外面去阻塞
                    return;
                }
                else
                {
                    ensureEnoughSize();
                }
            }
            // 2.将数据写入到缓冲区中
            std::copy(data, data + len, &_buffer[_writeIndex]);
            // 3.移动写指针的位置
            moveWriter(len);
        }

        // 返回可读数据的起始地址
        const char *begin()
        {
            return &_buffer[_readIndex];
        }

        // 可读数据的长度
        size_t writeAbleSize()
        {
            // 对扩容思路来说, 不存在可写空间大小, 因为总是可写的
            // 因此这个操作是针对固定大小缓冲区提供的
            return _buffer.size() - _writeIndex;
        }

        // 获取可读数据的长度
        size_t readAbleSize()
        {
            // 因为当前实现的缓冲区并不是循环缓冲区, 因为只会向后写, 不会存在可读数据长度计算错误的操作
            return _writeIndex - _readIndex;
        }

        // 修改读指针
        void moveReader(size_t len)
        {
            // 移动读指针的时候, 偏移的长度要小于等于可读数据的长度
            if (readAbleSize() < len)
            {
                std::cout << "读取的数据长度大于缓冲区中可读数据的长度!" << std::endl;
                abort();
            }
            _readIndex += len;
        }

        // 初始化缓冲区---只需要重置读写指针, 不需要改变缓冲区大小, 这样就不会涉及到空间的频繁申请与释放
        void reset()
        {
            _writeIndex = 0;
            _readIndex = 0;
        }

        // 交换缓冲区
        void swap(Buffer &buffer)
        {
            _buffer.swap(buffer._buffer);
            std::swap(_writeIndex, buffer._writeIndex);
            std::swap(_readIndex, buffer._readIndex);
        }

        // 判断缓冲区是否为空
        bool empty()
        {
            return _readIndex == _writeIndex;
        }

    private:
        // 修改写指针
        void moveWriter(size_t len)
        {
            if (_buffer.size() < len + _writeIndex)
            {
                std::cout << "写入当前数据后导致缓冲区溢出了!" << std::endl;
                abort();
            }
            _writeIndex += len;
        }

        // 动态扩容缓冲区
        void ensureEnoughSize()
        {
            size_t newSize = 0;
            if (_buffer.size() < THRESHOLD_BUFFER_SIZE)
            {
                newSize = 2 * _buffer.size();
            }
            else
            {
                newSize = _buffer.size() + INCREMENT_BUFFER_SIZE;
            }
            _buffer.resize(newSize);
        }

    private:
        BufferType _bufferType; //缓冲区的类型, 是固定大小的缓冲区还是动态增长的缓冲区
        std::vector<char> _buffer; // 缓冲区
        size_t _writeIndex;        // 可写数据指针
        size_t _readIndex;         // 可读数据指针
    };
}

#endif



